const activityLogService = require('../services/activityLog.service');
const logger = require('../utils/logger');
const mongoose = require('mongoose');

/**
 * 解析设备信息
 * @param {string} userAgent 用户代理字符串
 * @returns {Object} 设备信息对象
 */
function parseDeviceInfo(userAgent) {
  const deviceInfo = {
    platform: 'unknown',
    model: 'unknown',
    system: 'unknown'
  };

  try {
    if (!userAgent) return deviceInfo;

    // 记录原始UA以便调试
    logger.debug(`解析设备信息，User-Agent: ${userAgent}`);

    // API测试工具检测
    if (userAgent.includes('Reqable')) {
      deviceInfo.platform = 'API Tool';
      deviceInfo.model = 'Reqable';
      const versionMatch = userAgent.match(/Reqable\/([0-9\.]+)/);
      if (versionMatch && versionMatch[1]) {
        deviceInfo.system = `Reqable ${versionMatch[1]}`;
      }
      return deviceInfo;
    }

    if (userAgent.includes('Postman')) {
      deviceInfo.platform = 'API Tool';
      deviceInfo.model = 'Postman';
      return deviceInfo;
    }

    if (userAgent.includes('curl')) {
      deviceInfo.platform = 'API Tool';
      deviceInfo.model = 'cURL';
      return deviceInfo;
    }

    // 简单的平台检测
    if (userAgent.includes('iPhone')) {
      deviceInfo.platform = 'iOS';
      deviceInfo.model = 'iPhone';
    } else if (userAgent.includes('iPad')) {
      deviceInfo.platform = 'iOS';
      deviceInfo.model = 'iPad';
    } else if (userAgent.includes('Android')) {
      deviceInfo.platform = 'Android';
      
      // 尝试提取Android设备型号
      const modelMatch = userAgent.match(/Android [0-9\.]+; ([^;]+)/);
      if (modelMatch && modelMatch[1]) {
        deviceInfo.model = modelMatch[1].trim();
      }
    } else if (userAgent.includes('Windows')) {
      deviceInfo.platform = 'Windows';
    } else if (userAgent.includes('Macintosh')) {
      deviceInfo.platform = 'macOS';
    } else if (userAgent.includes('Linux')) {
      deviceInfo.platform = 'Linux';
    }

    // 尝试提取系统版本
    if (deviceInfo.platform === 'iOS') {
      const versionMatch = userAgent.match(/OS ([0-9_]+)/);
      if (versionMatch && versionMatch[1]) {
        deviceInfo.system = `iOS ${versionMatch[1].replace(/_/g, '.')}`;
      }
    } else if (deviceInfo.platform === 'Android') {
      const versionMatch = userAgent.match(/Android ([0-9\.]+)/);
      if (versionMatch && versionMatch[1]) {
        deviceInfo.system = `Android ${versionMatch[1]}`;
      }
    } else if (deviceInfo.platform === 'Windows') {
      const versionMatch = userAgent.match(/Windows NT ([0-9\.]+)/);
      if (versionMatch && versionMatch[1]) {
        const versionMap = {
          '10.0': 'Windows 10',
          '6.3': 'Windows 8.1',
          '6.2': 'Windows 8',
          '6.1': 'Windows 7',
          '6.0': 'Windows Vista',
          '5.2': 'Windows XP x64',
          '5.1': 'Windows XP'
        };
        deviceInfo.system = versionMap[versionMatch[1]] || `Windows NT ${versionMatch[1]}`;
      }
    }

    // 对于微信小程序，尝试提取更具体的信息
    if (userAgent.includes('MicroMessenger')) {
      deviceInfo.platform = 'WeChat';
      const wxVersionMatch = userAgent.match(/MicroMessenger\/([0-9\.]+)/);
      if (wxVersionMatch && wxVersionMatch[1]) {
        deviceInfo.model = `WeChat ${wxVersionMatch[1]}`;
      }
    }

    // 如果是浏览器，尝试提取浏览器信息
    const browserPatterns = [
      { name: 'Chrome', regex: /Chrome\/([0-9.]+)/ },
      { name: 'Firefox', regex: /Firefox\/([0-9.]+)/ },
      { name: 'Safari', regex: /Safari\/([0-9.]+)/ },
      { name: 'Edge', regex: /Edg\/([0-9.]+)/ }
    ];

    for (const pattern of browserPatterns) {
      const match = userAgent.match(pattern.regex);
      if (match) {
        if (deviceInfo.platform === 'unknown') {
          deviceInfo.platform = 'Browser';
        }
        deviceInfo.model = pattern.name;
        deviceInfo.system = `${pattern.name} ${match[1]}`;
        break;
      }
    }

  } catch (error) {
    logger.warn(`解析设备信息失败: ${error.message}`, {
      userAgent,
      error: error.stack
    });
  }

  return deviceInfo;
}

/**
 * 获取请求IP地址
 * @param {Object} req Express请求对象
 * @returns {string} IP地址
 */
function getClientIp(req) {
  // 添加详细的调试日志
  logger.debug('获取客户端IP地址', {
    'x-forwarded-for': req.headers['x-forwarded-for'],
    'x-real-ip': req.headers['x-real-ip'],
    'remoteAddress': req.connection?.remoteAddress,
    'socketRemoteAddress': req.socket?.remoteAddress
  });

  // 优先使用 X-Real-IP 头，这通常由 Nginx 等反向代理设置
  if (req.headers['x-real-ip']) {
    return req.headers['x-real-ip'];
  }

  // 其次使用 X-Forwarded-For，取第一个IP（最原始的客户端IP）
  if (req.headers['x-forwarded-for']) {
    const ips = req.headers['x-forwarded-for'].split(',');
    return ips[0].trim();
  }

  // 处理 IPv6 格式的本地地址
  const remoteAddress = req.socket?.remoteAddress || req.connection?.remoteAddress;
  if (remoteAddress) {
    // 如果是 IPv6 的本地地址，转换为更友好的格式
    if (remoteAddress === '::1' || remoteAddress === '::ffff:127.0.0.1') {
      return '127.0.0.1';
    }
    // 如果是 IPv6 格式的 IPv4 地址，提取 IPv4 部分
    if (remoteAddress.startsWith('::ffff:')) {
      return remoteAddress.substring(7);
    }
    return remoteAddress;
  }

  // 如果都获取不到，返回未知
  return 'unknown';
}

/**
 * 确定模块名称
 * @param {string} path API路径
 * @returns {string} 模块名称
 */
function determineModule(path) {
  const parts = path.split('/').filter(Boolean);
  
  if (parts.length >= 2 && parts[0] === 'api') {
    return parts[1]; // 返回api/后的第一个路径段，如api/foods -> foods
  }
  
  return 'other';
}

/**
 * 确定操作类型
 * @param {string} method HTTP方法
 * @returns {string} 操作类型
 */
function determineActionType(method) {
  switch (method.toUpperCase()) {
    case 'GET':
      return 'read';
    case 'POST':
      return 'create';
    case 'PUT':
    case 'PATCH':
      return 'update';
    case 'DELETE':
      return 'delete';
    default:
      return 'other';
  }
}

/**
 * 活动日志中间件
 * @param {Object} options 配置选项
 * @param {Array<string>} [options.ignorePaths=[]] 忽略的路径列表
 * @param {boolean} [options.logBody=false] 是否记录请求体内容
 * @returns {Function} Express中间件函数
 */
function activityLogger(options = {}) {
  const ignorePaths = options.ignorePaths || [];
  const logBody = options.logBody || false;
  
  return async (req, res, next) => {
    // 跳过不需要记录的路径
    if (ignorePaths.some(path => req.path.startsWith(path))) {
      return next();
    }
    
    // 保存原始的end方法以便后续恢复
    const originalEnd = res.end;
    let responseBody = '';
    let statusCode = 200;
    
    // 记录下当前时间作为请求开始时间
    const requestStart = Date.now();
    
    // 重写res.end方法来捕获响应状态和内容
    res.end = function(chunk, encoding) {
      // 恢复原始的end方法
      res.end = originalEnd;
      
      if (chunk) {
        try {
          responseBody = chunk.toString('utf8');
        } catch (e) {
          logger.warn(`无法转换响应内容: ${e.message}`);
        }
      }
      
      statusCode = res.statusCode;
      
      // 调用原始的end方法完成响应
      return res.end(chunk, encoding);
    };
    
    // 继续处理请求
    next();
    
    // 请求处理完毕后，异步记录活动
    res.on('finish', () => {
      // 使用 Promise.resolve().then() 确保异步操作不会阻塞响应完成
      Promise.resolve().then(async () => {
        try {
          // 如果用户未登录，则不记录但不抛出错误
          if (!req.user || !req.user._id) {
            return;
          }
          
          // 获取请求信息
          const userId = req.user._id;
          const userType = req.user.role === 'admin' ? 'admin' : 'user';
          const ipAddress = getClientIp(req);
          const userAgent = req.headers['user-agent'] || '';
          const deviceInfo = parseDeviceInfo(userAgent);
          const module = determineModule(req.path);
          const actionType = determineActionType(req.method);
          
          // 创建描述
          let description = `${req.method} ${req.path}`;
          if (statusCode >= 400) {
            description += ` (状态码: ${statusCode})`;
          }
          
          // 确定操作状态
          const status = statusCode < 400 ? 'success' : 'failed';
          
          // 在记录请求体之前进行安全检查
          let reqBody = null;
          if (logBody && req.body) {
            try {
              // 深拷贝请求体并去除敏感信息
              reqBody = JSON.parse(JSON.stringify(req.body));
              // 如果有密码字段，替换为占位符
              if (reqBody.password) reqBody.password = '******';
              if (reqBody.passwordConfirmation) reqBody.passwordConfirmation = '******';
            } catch (e) {
              logger.warn(`无法处理请求体进行日志记录: ${e.message}`);
            }
          }
          
          // 尝试解析响应体，但不中断流程
          let parsedResponse = null;
          if (logBody && responseBody) {
            try {
              parsedResponse = JSON.parse(responseBody);
              // 如果响应中包含敏感信息，也进行处理
              if (parsedResponse.token) parsedResponse.token = '******';
            } catch (e) {
              // 响应可能不是JSON格式，这是正常的
              parsedResponse = null;
            }
          }
          
          // 构建日志数据
          const logData = {
            userId,
            userType,
            actionType,
            module,
            details: {
              description,
              oldValue: reqBody,
              newValue: parsedResponse,
              object: null
            },
            ipAddress,
            userAgent,
            deviceInfo,
            status,
            errorMessage: status === 'failed' ? (typeof responseBody === 'string' ? responseBody.slice(0, 500) : null) : null
          };
          
          // 尝试从路径中提取对象 ID
          const pathParts = req.path.split('/').filter(Boolean);
          for (let i = 0; i < pathParts.length; i++) {
            const part = pathParts[i];
            if (mongoose.Types.ObjectId.isValid(part)) {
              logData.details.object = part;
              break;
            }
          }
          
          // 如果路径中没有找到 ID，尝试从查询参数中查找
          if (!logData.details.object) {
            Object.values(req.query).forEach(value => {
              if (mongoose.Types.ObjectId.isValid(value)) {
                logData.details.object = value;
              }
            });
          }
          
          // 如果还是没有找到 ID，尝试从请求体中查找
          if (!logData.details.object && reqBody) {
            const findId = (obj) => {
              if (!obj || typeof obj !== 'object') return null;
              for (const [key, value] of Object.entries(obj)) {
                if (key.toLowerCase().includes('id') && mongoose.Types.ObjectId.isValid(value)) {
                  return value;
                }
                if (typeof value === 'object') {
                  const nestedId = findId(value);
                  if (nestedId) return nestedId;
                }
              }
              return null;
            };
            const bodyId = findId(reqBody);
            if (bodyId) {
              logData.details.object = bodyId;
            }
          }
          
          // 记录执行时间
          const executionTime = Date.now() - requestStart;
          if (executionTime > 1000) { // 超过1秒的请求特别标记
            logData.details.description += ` (执行时间: ${executionTime}ms)`;
          }
          
          // 写入活动日志 - 使用Promise处理异步操作
          await activityLogService.logActivity(logData).catch(error => {
            logger.error(`记录活动日志失败: ${error.message}`, {
              error: error.stack,
              path: req.path,
              userId: req.user ? req.user._id : 'unknown'
            });
          });
        } catch (error) {
          // 确保错误不会影响主要应用流程
          logger.error(`处理活动日志时发生错误: ${error.message}`, {
            error: error.stack,
            path: req.path,
            userId: req.user ? req.user._id : 'unknown'
          });
        }
      });
    });
  };
}

/**
 * 手动记录活动的函数
 * @param {Object} req Express请求对象
 * @param {Object} options 活动选项
 * @param {string} options.actionType 操作类型
 * @param {string} options.module 模块名称
 * @param {string} options.description 操作描述
 * @param {Object} [options.object] 操作对象
 * @param {*} [options.oldValue] 操作前值
 * @param {*} [options.newValue] 操作后值
 * @param {string} [options.status='success'] 操作状态
 * @param {string} [options.errorMessage] 错误信息
 * @returns {Promise<Object>} 创建的日志记录
 */
async function logManualActivity(req, options) {
  // 如果用户未登录，记录警告但不阻止功能继续
  if (!req.user || !req.user._id) {
    logger.warn('尝试为未登录用户记录活动', { options });
    return null;
  }
  
  try {
    // 处理可能的对象类型数据，避免直接传递复杂对象
    let oldValue = options.oldValue;
    let newValue = options.newValue;
    
    // 如果是复杂对象，尝试安全地转换为JSON字符串
    if (oldValue && typeof oldValue === 'object') {
      try {
        oldValue = JSON.parse(JSON.stringify(oldValue));
      } catch (e) {
        logger.warn(`无法序列化oldValue: ${e.message}`);
        oldValue = null;
      }
    }
    
    if (newValue && typeof newValue === 'object') {
      try {
        newValue = JSON.parse(JSON.stringify(newValue));
      } catch (e) {
        logger.warn(`无法序列化newValue: ${e.message}`);
        newValue = null;
      }
    }
    
    const logData = {
      userId: req.user._id,
      userType: req.user.role === 'admin' ? 'admin' : 'user',
      actionType: options.actionType,
      module: options.module,
      details: {
        object: options.object || null,
        description: options.description,
        oldValue: oldValue,
        newValue: newValue
      },
      ipAddress: getClientIp(req),
      userAgent: req.headers['user-agent'] || '',
      deviceInfo: parseDeviceInfo(req.headers['user-agent'] || ''),
      status: options.status || 'success',
      errorMessage: options.errorMessage || null
    };
    
    // 使用setImmediate确保不阻塞主流程
    return new Promise((resolve) => {
      setImmediate(async () => {
        try {
          const result = await activityLogService.logActivity(logData);
          resolve(result);
        } catch (error) {
          logger.error(`手动记录活动失败: ${error.message}`, {
            error: error.stack,
            options: JSON.stringify(options)
          });
          resolve(null);
        }
      });
    });
  } catch (error) {
    logger.error(`准备手动记录活动数据失败: ${error.message}`, {
      error: error.stack,
      options: JSON.stringify(options)
    });
    return null;
  }
}

module.exports = {
  activityLogger,
  logManualActivity
}; 